---
title: "Dashboard"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
source: embed
---
```{r setup, include=FALSE}
library(tidyverse)
library(flexdashboard)
library(plotly)
library(p8105.datasets)
```
```{r}
# Import data
data("instacart")
```
```{r}
# Preprocess the dataset
instacart_df =
instacart |>
janitor::clean_names() |>
# handle missing values
mutate(
across(where(is.character), ~na_if(., ".")),
across(where(is.character), ~na_if(., "NA")),
across(where(is.character), ~na_if(., ""))
) |>
# create derived variables
mutate(
# order time categories
order_hour_category = case_when(
order_hour_of_day >= 6 & order_hour_of_day < 12 ~ "Morning (6-12)",
order_hour_of_day >= 12 & order_hour_of_day < 18 ~ "Afternoon (12-18)",
order_hour_of_day >= 18 & order_hour_of_day < 22 ~ "Evening (18-22)",
TRUE ~ "Night (22-6)"
),
# Day of week names
order_day_name = case_when(
order_dow == 0 ~ "Sunday",
order_dow == 1 ~ "Monday",
order_dow == 2 ~ "Tuesday",
order_dow == 3 ~ "Wednesday",
order_dow == 4 ~ "Thursday",
order_dow == 5 ~ "Friday",
order_dow == 6 ~ "Saturday"
),
# Weekend indicator
is_weekend = if_else(order_dow %in% c(0, 6), "Weekend", "Weekday"),
# Simplified department categories
dept_category = case_when(
department %in% c("produce", "dairy eggs") ~ "Fresh Foods",
department %in% c("snacks", "frozen", "ice cream ice") ~ "Snacks & Frozen",
department %in% c("bakery", "deli", "meat seafood") ~ "Bakery & Deli",
department %in% c("beverages", "alcohol") ~ "Beverages",
department %in% c("pantry", "dry goods pasta", "canned goods") ~ "Pantry Staples",
TRUE ~ "Other"
),
# change reorder type
is_reordered = as.logical(reordered)
) |>
select(
# IDs
order_id, product_id, user_id,
# Product information
product_name, aisle, department, dept_category,
# Order timing
order_hour_of_day, order_hour_category,
order_dow, order_day_name, is_weekend,
# Order characteristics
order_number, add_to_cart_order,
days_since_prior_order,
# Reorder behavior
reordered, is_reordered
)
```
Column {data-width=450}
-----------------------------------------------------------------------
### Top 20 Most Popular Products
```{r}
top20_products =
instacart_df |>
count(product_name, sort = TRUE) |>
slice_head(n = 20) |>
mutate(
product_name = fct_reorder(product_name, n)
) |>
plot_ly(
x = ~n,
y = ~product_name,
type = "bar",
orientation = "h",
marker = list(
color = ~n,
colorscale = list(
c(0, "#FEF0D9"),
c(0.5, "#FD8D3C"),
c(1, "#D94701")
),
line = list(color = "#8B4513", width = 1)
),
text = ~paste0(product_name, "<br>Orders: ", n),
hovertemplate = "<b>%{y}</b><br>Total Orders: %{x:,}<extra></extra>"
) |>
layout(
title = list(
text = "<b>Top 20 Most Popular Products on Instacart</b>",
font = list(size = 18)
),
xaxis = list(
title = "Number of Orders",
titlefont = list(size = 14),
gridcolor = "#E5E5E5"
),
yaxis = list(
title = "",
titlefont = list(size = 14),
tickfont = list(size = 11)
),
plot_bgcolor = "#FAFAFA",
paper_bgcolor = "white",
margin = list(l = 200, r = 50, t = 80, b = 60),
hovermode = "closest"
)
top20_products
```
### Order Time vs Department
```{r}
time_dept_data =
instacart_df |>
count(order_hour_of_day, department) |>
group_by(department) |>
mutate(
dept_total = sum(n),
pct_of_dept = round(n / dept_total * 100, 1)
) |>
ungroup()
scatterplot1 =
time_dept_data |>
plot_ly(
x = ~order_hour_of_day,
y = ~department,
color = ~department,
type = "scatter",
mode = "markers",
size = ~ n,
sizes = c(10, 400),
marker = list(
opacity = 0.7
),
text = ~paste0(
"<b>", department, "</b><br>",
"Hour: ", order_hour_of_day, ":00<br>",
"Orders: ", scales::comma(n), "<br>",
"% of dept: ", pct_of_dept, "%"
),
hovertemplate = "%{text}<extra></extra>"
) |>
layout(
title = list(
text = "<b>Order Patterns: Time of Day vs Department</b><br><sub>Bubble size represents order volume</sub>",
font = list(size = 16)
),
xaxis = list(
title = "Hour of Day (0-23)",
titlefont = list(size = 14),
tickmode = "linear",
tick0 = 0,
dtick = 2
),
yaxis = list(
title = "Department",
titlefont = list(size = 14),
tickfont = list(size = 11),
categoryorder = "total ascending"
)
)
scatterplot1
```
Column {data-width=450}
-----------------------------------------------------------------------
### 24-Hour Order Trend on Instacart
```{r}
hourly_orders =
instacart_df |>
count(order_hour_of_day) |>
mutate(
pct_of_total = round(n / sum(n) * 100, 1)
) |>
plot_ly(
x = ~order_hour_of_day,
y = ~n,
type = "scatter",
mode = "lines+markers",
line = list(
color = "#1f77b4",
width = 3
),
marker = list(
size = 8,
color = "#1f77b4",
line = list(color = "white", width = 2)
),
text = ~paste0(
"Hour: ", order_hour_of_day, ":00<br>",
"Orders: ", scales::comma(n), "<br>",
"Percentage: ", pct_of_total, "%"
),
hovertemplate = "%{text}<extra></extra>"
) |>
layout(
title = list(
text = "<b>24-Hour Order Trend on Instacart</b><br><sub>Shopping patterns throughout the day</sub>",
font = list(size = 16)
),
xaxis = list(
title = "Hour of Day",
titlefont = list(size = 14),
tickmode = "linear",
tick0 = 0,
dtick = 2,
range = c(-0.5, 23.5),
gridcolor = "#E5E5E5"
),
yaxis = list(
title = "Number of Orders",
titlefont = list(size = 14),
gridcolor = "#E5E5E5",
tickformat = ","
),
plot_bgcolor = "#FAFAFA",
paper_bgcolor = "white",
margin = list(l = 80, r = 50, t = 100, b = 60),
hovermode = "x unified",
shapes = list(
# Adding a shaded area for peak hours
list(
type = "rect",
x0 = 10, x1 = 16.5,
y0 = 0, y1 = 1,
yref = "paper",
fillcolor = "rgba(255, 165, 0, 0.1)",
line = list(width = 0),
layer = "below"
)
),
annotations = list(
list(
x = 13,
y = 1.05,
yref = "paper",
text = "Peak Hours",
showarrow = FALSE,
font = list(size = 11, color = "#FF8C00")
)
)
)
hourly_orders
```
### Weekly Order Pattern on Instacart
```{r}
weekly_orders =
instacart_df |>
count(order_day_name) |>
mutate(
pct_of_total = round(n / sum(n) * 100, 1),
# Reorder days from Monday to Sunday
order_day_name = factor(
order_day_name,
levels = c("Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday")
)
) |>
arrange(order_day_name) |>
plot_ly(
x = ~order_day_name,
y = ~n,
type = "scatter",
mode = "lines+markers",
line = list(
color = "#2ca02c",
width = 4
),
marker = list(
size = 12,
color = "#2ca02c",
symbol = "circle",
line = list(color = "white", width = 2)
),
text = ~paste0(
"<b>", order_day_name, "</b><br>",
"Orders: ", scales::comma(n), "<br>",
"Percentage: ", pct_of_total, "%"
),
hovertemplate = "%{text}<extra></extra>"
) |>
layout(
title = list(
text = "<b>Weekly Order Pattern on Instacart</b><br><sub>Monday to Sunday shopping trends</sub>",
font = list(size = 16)
),
xaxis = list(
title = "Day of Week",
titlefont = list(size = 14),
tickangle = 0
),
yaxis = list(
title = "Number of Orders",
titlefont = list(size = 14),
gridcolor = "#E5E5E5",
tickformat = ","
),
plot_bgcolor = "#FAFAFA",
paper_bgcolor = "white",
margin = list(l = 80, r = 50, t = 100, b = 80),
hovermode = "x unified"
)
weekly_orders
```